00001
00009 package jvn;
00010
00011 import java.rmi.Naming;
00012 import java.rmi.RemoteException;
00013 import java.rmi.server.UnicastRemoteObject;
00014 import java.util.HashMap;
00015 import java.util.Iterator;
00016 import java.util.LinkedList;
00017 import java.util.concurrent.Semaphore;
00018 import java.io.IOException;
00019 import java.io.Serializable;
00020
00027 class JvnInvalidateReaderThread extends Thread
00028 {
00032 private int objectID;
00033
00039 private Semaphore semaphore;
00040
00045 private JvnRemoteServer server;
00046
00056 JvnInvalidateReaderThread( Semaphore sema, JvnRemoteServer serv, int joi )
00057 {
00058 server = serv;
00059 objectID = joi;
00060 semaphore = sema;
00061 }
00062
00068 public void run() {
00069 try {
00070 server.jvnInvalidateReader(objectID);
00071 } catch(JvnException e) {
00072 System.out.println("Javanaise error while invalidating reader: " + e);
00073 }
00074 catch(RemoteException e) {
00075 System.out.println("Network error while invalidating reader: " + e);
00076 }
00077
00078 semaphore.release();
00079 }
00080 }
00081
00086 class JvnServers {
00091 public JvnServers(JvnRemoteServer server, JvnObject obj) throws JvnException
00092 {
00093 jvnListOfServers.add(server);
00094 jvnObject = obj;
00095 if( obj!=null ) {
00096 try {
00097 latestJvnObjectContent = obj.jvnGetObjectState();
00098 } catch( JvnException e ) {
00099 latestJvnObjectContent = null;
00100 }
00101 }
00102 }
00103
00108 public LinkedList<JvnRemoteServer> jvnListOfServers = new LinkedList<JvnRemoteServer>();
00109
00113 public JvnObject jvnObject = null;
00114
00120 public JvnObjectState lockState = null;
00121
00125 public Serializable latestJvnObjectContent = null;
00126 }
00127
00132 public class JvnCoordImpl extends UnicastRemoteObject implements JvnRemoteCoord {
00136 private static final long serialVersionUID = -115305878534728396L;
00137
00144 private int currID = -1;
00145
00149 private static JvnCoordImpl jo = null;
00150
00155 private HashMap<String,JvnServers> jvnServersOfNames = new HashMap<String, JvnServers>();
00156
00163 private HashMap<Integer,JvnServers> jvnServersOfIdentifiers = new HashMap<Integer, JvnServers>();
00164
00168 private JvnCoordImpl() throws Exception {
00169 Naming.rebind("AT_LD_jvnCoordinator", this);
00170 System.out.println("Javanaise Coordinator is ready.");
00171 currID = 0;
00172 }
00173
00180 public static void main(String argv[]) throws Exception {
00181 if(jo==null){
00182 jo = new JvnCoordImpl();
00183 System.out.println("Press ENTER to terminate the Javanaise Coordinator.");
00184 try {
00185 System.in.read();
00186 } catch (IOException e) {}
00187 }
00188 }
00189
00193 public int jvnGetObjectId()
00194 throws java.rmi.RemoteException,jvn.JvnException {
00195 synchronized(this) {
00196 return (++currID);
00197 }
00198 }
00199
00209 public void jvnRegisterObject(String jon, JvnObject jo, JvnRemoteServer js)
00210 throws java.rmi.RemoteException,jvn.JvnException{
00211
00212
00213 synchronized(jvnServersOfIdentifiers) {
00214
00215
00216 if( jo==null ) {
00217 throw new JvnException("Invalid object!");
00218 } else if( jo.jvnGetObjectId() < 0 ) {
00219 throw new JvnException( "Invalid object ID! Please call jvnGetObjectId " +
00220 "to get a new object ID and associate it with the " +
00221 "Javanaise object using the jvnSetObjectId method." );
00222 } else if( jvnServersOfIdentifiers.containsKey(jo.jvnGetObjectId()) ) {
00223 throw new JvnException("Object with such an ID is already registered with this coordinator!");
00224 } else if( jvnServersOfNames.containsKey(jon) ) {
00225 throw new JvnException("Object with such a name is already registered with this coordinator!");
00226 }
00227
00228 System.out.println("Registering object \""+jon+"\" (Object ID: "+jo.jvnGetObjectId()+")");
00229
00230
00231 JvnServers servers = new JvnServers(js,jo);
00232 servers.lockState = JvnObjectState.STATE_WLOCKT;
00233 jvnServersOfNames.put(jon, servers);
00234 jvnServersOfIdentifiers.put(jo.jvnGetObjectId(), servers);
00235 }
00236 }
00237
00247 public JvnObject jvnLookupObject(String jon, Class<? extends JvnObject> type, JvnRemoteServer js)
00248 throws java.rmi.RemoteException,jvn.JvnException{
00249
00250 if( js==null ) {
00251 throw new JvnException( "Invalid server! When calling this method " +
00252 "from a JvnRemoteServer, set the second "+
00253 "argument to \"this\".");
00254 }
00255
00256 System.out.println("Looked up object: "+jon);
00257
00258
00259
00260 synchronized(jvnServersOfIdentifiers) {
00261 JvnServers servers = jvnServersOfNames.get(jon);
00262 if( servers != null ) {
00263 System.out.println("Found object with name \"" + jon + "\"");
00264 return servers.jvnObject;
00265 } else {
00266 System.out.println("Not found object with name \"" + jon + "\"");
00267 return null;
00268 }
00269 }
00270 }
00271
00280 public Serializable jvnLockRead(int joi, JvnRemoteServer js)
00281 throws java.rmi.RemoteException, JvnException{
00282
00283 if( js==null ) {
00284 throw new JvnException( "Invalid server! When calling this method " +
00285 "from a JvnRemoteServer, set the second "+
00286 "argument to \"this\".");
00287 }
00288
00289 synchronized(jvnServersOfIdentifiers)
00290 {
00291 JvnServers servers = jvnServersOfIdentifiers.get(joi);
00292 if( servers == null ) {
00293 throw new JvnException( "The given object identifier is not registered" +
00294 "with this coordinator!" );
00295 } else if( servers.lockState == JvnObjectState.STATE_NOLOCK ) {
00296
00297 System.out.println("Read lock: getting lock (was not locked before).");
00298 servers.lockState = JvnObjectState.STATE_RLOCKT;
00299 servers.jvnListOfServers.clear();
00300 servers.jvnListOfServers.add(js);
00301 } else if( servers.lockState == JvnObjectState.STATE_RLOCKT ) {
00302
00303 System.out.println("Read lock: adding reference.");
00304 servers.jvnListOfServers.add(js);
00305 } else if( servers.lockState == JvnObjectState.STATE_WLOCKT ) {
00306 try {
00307 System.out.println("Read lock: invalidating writer for reader.");
00308 JvnRemoteServer server = servers.jvnListOfServers.iterator().next();
00309 servers.latestJvnObjectContent = server.jvnInvalidateWriterForReader(joi);
00310 servers.lockState = JvnObjectState.STATE_RLOCKT;
00311 if( server.equals(js)) {
00312 System.out.println("Read lock: downgraded from write lock.");
00313 } else {
00314 System.out.println("Read lock: adding reference.");
00315 servers.jvnListOfServers.add(js);
00316 }
00317 } catch( Exception e ) {
00318
00319 throw new JvnException("Error getting the read lock!\n"+e);
00320 }
00321 } else {
00322 throw new JvnException("Unexpected lock state: " + servers.lockState + " !\n");
00323 }
00324
00325 return servers.latestJvnObjectContent;
00326 }
00327 }
00328
00337 public Serializable jvnLockWrite(int joi, JvnRemoteServer js)
00338 throws java.rmi.RemoteException, JvnException{
00339
00340 if( js==null ) {
00341 throw new JvnException( "Invalid server! When calling this method " +
00342 "from a JvnRemoteServer, set the second "+
00343 "argument to \"this\".");
00344 }
00345
00346 synchronized(jvnServersOfIdentifiers)
00347 {
00348 JvnServers servers = jvnServersOfIdentifiers.get(joi);
00349 if( servers == null ) {
00350 throw new JvnException( "The given object identifier is not registered" +
00351 "with this coordinator!" );
00352 } else if( servers.lockState == JvnObjectState.STATE_NOLOCK ) {
00353
00354 System.out.println("Write lock: getting lock (was not locked before).");
00355 servers.lockState = JvnObjectState.STATE_WLOCKT;
00356 } else if( servers.lockState == JvnObjectState.STATE_RLOCKT ) {
00357 System.out.println("Write lock: invalidating readers.");
00358
00359 int numberOfReaders = 0;
00360 Semaphore s = new Semaphore(0);
00361
00362 Iterator<JvnRemoteServer> i = servers.jvnListOfServers.iterator();
00363 while(i.hasNext()) {
00364 numberOfReaders++;
00365 (new JvnInvalidateReaderThread(s,i.next(),joi)).start();
00366 }
00367
00368
00369 if( numberOfReaders>0 ) {
00370 try {
00371 s.acquire(numberOfReaders);
00372 } catch (InterruptedException e) {}
00373 }
00374 System.out.println("Write lock: invalidated "+numberOfReaders+" readers.");
00375 } else if( servers.lockState == JvnObjectState.STATE_WLOCKT ) {
00376 try {
00377
00378 System.out.println("Write lock: invalidating writer.");
00379 servers.latestJvnObjectContent = servers.jvnListOfServers.iterator().next().jvnInvalidateWriter(joi);
00380 System.out.println("Write lock: invalidated writer.");
00381 } catch( Exception e ) {
00382 throw new JvnException("Error getting the write lock!\n"+e);
00383 }
00384 } else {
00385 throw new JvnException("Unexpected lock state: "+servers.lockState+" !\n");
00386 }
00387
00388 servers.jvnListOfServers.clear();
00389 servers.jvnListOfServers.add(js);
00390 servers.lockState = JvnObjectState.STATE_WLOCKT;
00391
00392 return servers.latestJvnObjectContent;
00393 }
00394 }
00395
00402 public void jvnServerTerminated(JvnRemoteServer js) throws RemoteException, JvnException {
00403
00404
00405
00406 System.out.println("A server has terminated: unregistering.");
00407
00408 synchronized(jvnServersOfIdentifiers) {
00409 Iterator<JvnServers> i = jvnServersOfIdentifiers.values().iterator();
00410 Iterator<JvnRemoteServer> j = null;
00411 JvnRemoteServer server = null;
00412 JvnServers servers = null;
00413
00414
00415 while(i.hasNext()) {
00416 servers = i.next();
00417 j = servers.jvnListOfServers.iterator();
00418
00419
00420 while(j.hasNext()) {
00421 server = j.next();
00422
00423
00424 if(server.equals(js)) {
00425 if(servers.lockState == JvnObjectState.STATE_WLOCKT) {
00426 System.out.println("A server has terminated: invalidating writer.");
00427 servers.latestJvnObjectContent = servers.jvnObject.jvnInvalidateWriter();
00428 }
00429 servers.jvnListOfServers.remove(server);
00430 if(servers.jvnListOfServers.isEmpty()) {
00431 servers.lockState = JvnObjectState.STATE_NOLOCK;
00432 }
00433 break;
00434 }
00435 }
00436 }
00437 }
00438 System.out.println("A server has terminated: unregister complete.");
00439 }
00440 }